#version 430

in vec2 TexCoords;

in vec3 tanVert;
in vec3 tanView;
in vec3 tanLight;
out vec4 FragColour;

uniform bool UseNormalTexture;
uniform sampler2D NormalTexture;

uniform bool UseDepthTexture;
uniform sampler2D DepthTexture;

uniform bool UseSpecularTexture;
uniform sampler2D SpecularTexture;

uniform bool UseDiffuseTexture;
uniform sampler2D DiffuseTexture;

uniform vec3 viewPos;
in vec4 ViewSpaceVertPos;

////////////////// Fog data
uniform vec3 fogColour;
uniform float fogDensity;

//////////////// Diffuse data
in vec3 VertPos;
in vec3 N;
// Light information
uniform vec3 LightPosition;				// Light position in eye view
uniform vec3 Ia;						// Ambient intensity
uniform vec3 Id;						// Diffuse and specular light intensity
uniform float MinAttenuation;			// Minimum attenuation for the light (really intense light like sun, moon, etc)
// Object material
uniform vec3 Kd;						// Diffuse reflection coefficient (0 - 1)
uniform vec3 Ka;						// Ambient Reflection Coefficient
uniform vec3 Ks;						// Specular Reflection Coefficient
////////////////

// Editor variables
uniform bool bPointed;
uniform bool bSelected;

// read a normal from RGB
vec3 RGBToNormal(vec3 rgb) { return 2.0 * rgb - 1.0; }

vec3 calcFog(vec3 colour) {
	float fogCoord = abs(ViewSpaceVertPos.z / ViewSpaceVertPos.w);
	float factor = exp(-pow(fogDensity*fogCoord, 2.0)); // e^(-[(fd*fc)^2]); 1/(e^[(fd*fc)^2])
//	float factor = 1.f; // until this is fixed
	factor = clamp(factor, 0.0, 1.0);
	return mix(fogColour, colour, factor);
}

// steep parallax mapping
vec2 steepMap(vec2 initCoords, vec3 viewDir) {
	//Parralax mapping as done in Shader Programming

	float height_scale = 0.02;
	//Using a minimum and a maximum, get a number of layers scaled with the position of the camera
		float fMinLayers = 16.f;
		float fMaxLayers = 32.f;
		float fNumLayers = mix(fMaxLayers, fMinLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));

		//The size of each layer
		float fLayerDepth = 1.0 / fNumLayers;
		//The depth of the current layer we are checking
		float fCurrentLayerDepth = 0.0f; 
		//The amount the texture coordinates are shifted per layer
		vec2 p = viewDir.xy * height_scale;
		vec2 deltaTexCoords = p / fNumLayers;

		//The texture coords, as a local editable variable
		vec2 currentTexCoords = initCoords;
		float fCurrentDepthValue = 1.0 - texture(DepthTexture, currentTexCoords).r;

		//While we are below the current depth value for this vertex, we shift the current texture coords by the delta value,
		//and re-sample the texture for the next layer
		while(fCurrentLayerDepth < fCurrentDepthValue)
		{
			currentTexCoords -= deltaTexCoords;
			fCurrentDepthValue = 1.0 - texture(DepthTexture, currentTexCoords).r;
			fCurrentLayerDepth += fLayerDepth;  
		}

		//Parallax Occlusion mapping
		//The previous texture coords, by adding the delta back on top
		vec2 prevTexCoords = currentTexCoords + deltaTexCoords;

		//The depths before and after intersection
		float fAfterDepth = fCurrentDepthValue - fCurrentLayerDepth;
		float fBeforeDepth = (1.0 - texture(DepthTexture, prevTexCoords).r) - fCurrentLayerDepth + fLayerDepth;

		//Interpolate between the texture coordinates
		float fWeight = fAfterDepth / (fAfterDepth - fBeforeDepth);
		currentTexCoords = prevTexCoords * fWeight + currentTexCoords * (1.0 - fWeight);

		return currentTexCoords;
}

void main() {
	vec3 LightVector = LightPosition - VertPos;		//Calculate the light vector

	vec3 L = normalize(LightVector);      
	vec3 V = -normalize(viewPos - VertPos);	//Normalize perspective vector
	//vec3 V = -normalize(VertPos);	//Normalize perspective vector

	vec3 tV = normalize(tanView - tanVert);
	vec2 Coords = TexCoords;
	if (UseDepthTexture)
	{
		Coords = steepMap(TexCoords, tV);
		LightVector = tanLight - VertPos;		//Use tangent light position if using depth map
	}

	//Cut off textures if outside of uv bounds (0.0 - 1.0)
	//if(Coords.x > 1.0 || Coords.y > 1.0 || Coords.x < 0.0 || Coords.y < 0.0)
    //discard;
	
	vec3 dfuse = vec3(1.f);	
	if (UseDiffuseTexture)
		dfuse = texture(DiffuseTexture, Coords).rgb;
	
	vec3 specl = dfuse;
	if (UseSpecularTexture)
		specl = texture(SpecularTexture, Coords).rgb;

	vec3 Norm = N;
	if (UseNormalTexture)
		Norm = RGBToNormal(texture(NormalTexture, Coords).rgb);

	vec3 AmbientTerm = (Ia * Ka * dfuse);									//Ambient
	float A = 1.0f - pow(length(LightVector) / 100.f, 2);
	float Attenuation = max(A, MinAttenuation);
	vec3 DiffuseTerm = Attenuation * dfuse * Kd * max(dot(Norm,L), 0.0);	//Diffuse
	vec3 R = -reflect(L, Norm);
	vec3 SpecularTerm = Attenuation * Id * specl * Ks * pow(max(dot(R, V), 0.0), 2);
	SpecularTerm = clamp(SpecularTerm, 0.0, 1.0);							//Specular

	if (bPointed) SpecularTerm += vec3(0.2f);
	if (bSelected) SpecularTerm += vec3(0.0f, 0.3f, 0.0f);

	vec3 I = AmbientTerm + DiffuseTerm + SpecularTerm;
	I = clamp(I, 0.0, 1.0);

	FragColour = vec4(calcFog(I), 1.0);
}
